package net.betou.common.web.cos;

import java.io.OutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;

/**
 * A <code>MacBinaryDecoderOutput</code> filters MacBinary files to normal files
 * on the fly; optimized for speed more than readability.
 * 
 * @author Jason Hunter
 */
public class MacBinaryDecoderOutputStream extends FilterOutputStream{
	private int bytesFiltered = 0;
	private int dataForkLength = 0;

	public MacBinaryDecoderOutputStream( OutputStream out ) {
		super( out );
	}

	public void write( int b ) throws IOException {
		// Bytes 83 through 86 are a long representing the data fork length
		// Check <= 86 first to short circuit early in the common case
		if( bytesFiltered <= 86 && bytesFiltered >= 83 ){
			int leftShift = ( 86 - bytesFiltered ) * 8;
			dataForkLength = dataForkLength | ( b & 0xff ) << leftShift;
		}

		// Bytes 128 up to (128 + dataForkLength - 1) are the data fork
		else if( bytesFiltered < ( 128 + dataForkLength ) && bytesFiltered >= 128 ){
			out.write( b );
		}

		bytesFiltered++;
	}

	public void write( byte b[] ) throws IOException {
		write( b, 0, b.length );
	}

	public void write( byte b[], int off, int len ) throws IOException {
		// If the write is for content past the end of the data fork, ignore
		if( bytesFiltered >= ( 128 + dataForkLength ) ){
			bytesFiltered += len;
		}
		// If the write is entirely within the data fork, write it directly
		else if( bytesFiltered >= 128 && ( bytesFiltered + len ) <= ( 128 + dataForkLength ) ){
			out.write( b, off, len );
			bytesFiltered += len;
		}
		// Otherwise, do the write a byte at a time to get the logic above
		else{
			for ( int i = 0; i < len; i++ ){
				write( b[ off + i ] );
			}
		}
	}
}
